#ifndef ASNODE_H
#define ASNODE_H
#include "global.h"
#include "token.h"
#include "as-node-mem.h"
#include <vector>
#include <list>
#include <set>
#include <string>

namespace tinyscript {
namespace internal{

class NodeUnary;
class NodeExpression;
class NodeFuncInvoke;
class NodeAssignment;
class NodeFor;
class NodeForeach;
class NodeWhile;
class NodeIf;
class NodeElseIf;
class NodeElse;
class NodeKeyword;
class NodeDefineFunc;
class NodeReturn;
class NodeDefineList;
class NodeDefineListAssignment;
class NodeListAccessor;
class NodeInt;
class NodeFloat;
class NodeBoolean;
class NodeString;
class NodeNull;
class NodeSymbol;
class NodeVarDeclaration;
class NodeChunk;

// This object is used to declare the memory page of all the allocated node.
// It uses allocate multi-times and release at once to avoid overhead on heap.
// Before allocation, the ASNodeZone must be initialized to the ASNode class.
// Therefore, the user should call this function before everything begins.
class ASNodePage {
public:
    ASNodePage();
	// This function will return a memory inside of the pool
	// The size cannot be too large, it should be decided 
	// during before release the code and make it static 
    void* New( size_t size );
    void Delete( size_t size , void* ptr );
private:
	// Round the size to default alignment size
    size_t Round( size_t size ) {
        return (((size)+(kAlignmentSize))&~(kAlignmentSize));
    }

private:
    ASNodeMemoryPool base_pool_;
    std::vector<ASNodeMemoryPool*> mempool_list_;
    static const int kAlignmentSize = 4;
    static const int kMaxPageObjectSize = 256;

	DISALLOW_COPY_AND_ASSIGN(ASNodePage);
};

#define DECLARE_ASNODE_MEMORY_FUNC(N) \
    static void* operator new(size_t size) { \
    return ASNode::GetNodePage()->New(size);} \
    static void operator delete(void* ptr) { \
    ASNode::GetNodePage()->Delete(sizeof(N),ptr);}


class ASNode {
public:

    enum {
        NODE_INT,
        NODE_FLOAT,
        NODE_BOOLEAN,
        NODE_SYMBOL,
		NODE_STRING,
		NODE_NULL,
        NODE_KEYWORD,
		NODE_LHS_VARIABLE, 
        NODE_EXPRESSION ,
        NODE_UNARY ,
        NODE_FUNC_INVOKE ,
        NODE_ASSIGNMENT ,
		NODE_VAR_DECLARATION,
        NODE_FOR ,
        NODE_FOREACH,
        NODE_WHILE,
        NODE_IF,
		NODE_ELSEIF,
		NODE_ELSE,
        NODE_DEFINE_FUNC,
		NODE_RETURN ,
        NODE_DEFINE_LIST,
		NODE_DEFINE_LIST_ASSIGNMENT,
		NODE_LIST_ACCESSOR,
		NODE_CHUNK,
        NODE_MODULE
    };

public:
	// This function will not invoke any DEBUG build 
	// fatal error. Simply puts it , using this function
	// will not raise assertion failed even the cast can
	// not be achieved 
    template< typename T >
    inline T* TryCast() const;
	// If the cast cannot achieved, an assertion error will
	// raise .Use this will ensure the code to be safe 
    template< typename T >
    inline T* EnsureCast() const;
    const ASNode* parent() const {
        return parent_;
    }

    void set_parent( const ASNode* n ) {
        parent_ = n;
    }
	// This function is used to print out diagnostic information
	// of all the node. It is very important the derive class
	// should implement its own version of this function 
	virtual void PrintNode( std::ostream& os , int level = 0) {
        USE(level);
		os<<"N/A\n";
	}

	int node_type() const {
		return node_type_;
	}

    virtual ~ASNode() = 0 ;

public:

    static void BindASNodePage( ASNodePage* p ) {
		assert( kNodePage == NULL );
		kNodePage = p;
	}

	static void ClearASNodePage() {
		kNodePage = NULL;
	}

public:

	ASNode( int s )
		:node_type_(s),
		parent_(NULL){}

protected:
	// This function is only used for the derived class
	// which is used to grab the real memory inside of 
	// the memory pool. The owner of the ASNodePage is
	// the owner of all the node. Typically it is the
	// parser, if the parser expires, the node page will
	// be returned back to the system and of course all
	// the memory of node is not available anymore.
    static ASNodePage* GetNodePage() {
		assert(kNodePage);
        return kNodePage;
    }

protected:

	void PrintPrefix( std::ostream& os , int level ) {
		for( int i = 0 ; i < level ; ++i )
			os<<"    ";
	}


private:
    int node_type_;
    const ASNode* parent_;
private:
    static ASNodePage* kNodePage;
};

template<typename T> struct asnode_id;


#define DECLARE_ASNODE(N,V) \
    template<> struct asnode_id<N>{ \
    typedef N type_value; \
    static const int type_id = V; };


class NodeUnary : public ASNode {
public:
    NodeUnary()
        :ASNode(ASNode::NODE_UNARY)
        ,child_(NULL)
		,operation_(Token::TT_ERROR){}

    ASNode* child() const {
        return child_;
    }
    void set_child( ASNode* n ) {
        n->set_parent(this);
        child_ = n;
    }

    int operation() const {
        return operation_;
    }

    void set_operation( int t ) {
        operation_ = t;
    }


	virtual void PrintNode( std::ostream& os , int level =0 ) {
		PrintPrefix(os,level);
		os<<"Unary:{\n";
		PrintPrefix(os,level);
		os<<"Operation:"<<Token::GetTokenName(operation_)<<"\n";
		PrintPrefix(os,level);
		os<<"Child:\n";
		child_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"}\n";
	}

public:

	virtual ~NodeUnary();

    DECLARE_ASNODE_MEMORY_FUNC(NodeUnary)

private:
    ASNode* child_;
    int operation_;
};

class NodeExpression : public ASNode {
public:
    NodeExpression():
        ASNode(ASNode::NODE_EXPRESSION),
        left_child_(NULL),
        right_child_(NULL),
		operation_(Token::TT_ERROR){}
    ASNode* left_child() const {
        return left_child_;
    }
    ASNode* right_child() const{
        return right_child_;
    }
    void set_left_child( ASNode* n )  {
        n->set_parent(this);
        left_child_ = n;
    }
    void set_right_child( ASNode* r )  {
        r->set_parent(this);
        right_child_ = r;
    }
    int opreation() const {
        return operation_;
    }
    void set_opreation( int t ) {
        operation_ = t;
    }

	virtual void PrintNode( std::ostream& os , int level = 0 ) {
		PrintPrefix(os,level);
		os<<"Expression:{\n";
		PrintPrefix(os,level);
		os<<"Operator:"<<Token::GetTokenName(operation_)<<"\n";
		PrintPrefix(os,level);
		os<<"LeftChild:\n";
		left_child_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"RightChild:\n";
		right_child_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"}\n";
	}

public:

    virtual ~NodeExpression();

    DECLARE_ASNODE_MEMORY_FUNC(NodeExpression)

private:
    ASNode* left_child_ , *right_child_;
    int operation_;
};

class NodeFuncInvoke : public ASNode {
public:
	NodeFuncInvoke():
	  ASNode(ASNode::NODE_FUNC_INVOKE){}

	  typedef std::list<ASNode*> NodeList;

	  const NodeList& node_list() const {
		  return node_list_;
	  }

	  void AppendChild( ASNode* c ) {
		  c->set_parent(this);
		  node_list_.push_back(c);
	  }

	  const std::string& func_name() const {
		  return func_name_;
	  }

	  void set_func_name( const std::string& n ) {
		  func_name_ = n;
	  }


	  virtual void PrintNode( std::ostream& os , int level =0 );

public:

	  virtual ~NodeFuncInvoke();


	  DECLARE_ASNODE_MEMORY_FUNC(NodeFuncInvoke)

private:
	NodeList node_list_;
	std::string func_name_;
};

class NodeListAccessor : public ASNode {
public:
	NodeListAccessor():
	  ASNode( ASNode::NODE_LIST_ACCESSOR ) ,
	  index_node_(NULL){}
public:
	const std::string& name() const {
		return name_;
	}
	void set_name( const std::string& n ) {
		name_ = n;
	}
	ASNode* index_node() const {
		index_node_->set_parent(this);
		return index_node_;
	}
	void set_index_node( ASNode* n ) {
		n->set_parent(this);
		index_node_ = n;
	}

	virtual void PrintNode( std::ostream& os , int level =0 ) {
		PrintPrefix(os,level);
		os<<"List Accessor:{\n";
		PrintPrefix(os,level);
		os<<"Name:"<<name_<<"\n";
		PrintPrefix(os,level);
		os<<"Index Node:\n";
		index_node_->PrintNode(os);
		PrintPrefix(os,level);
		os<<"}\n";
	}

public:

	virtual ~NodeListAccessor();

	DECLARE_ASNODE_MEMORY_FUNC(NodeListAccessor)
private:
	ASNode* index_node_; 
	std::string name_;
};

class NodeAssignment : public ASNode {
public:
    NodeAssignment():
        ASNode(ASNode::NODE_ASSIGNMENT),
        left_child_(NULL),
        right_child_(NULL){}

public:

    ASNode* left_child() const {
        return left_child_;
    }

    ASNode* right_child() const {
        return right_child_;
    }

    void set_left_child( ASNode* n ) {
        n->set_parent(this);
        left_child_ = n;
    }

    void set_right_child( ASNode* n ) {
        n->set_parent(this);
        right_child_ = n;
    }

	virtual void PrintNode(std::ostream& os , int level=0 ) {
		PrintPrefix(os,level);
		os<<"Assignment:{\n";
		PrintPrefix(os,level);

		os<<"Left Hand Side:\n";
		left_child_->PrintNode(os,level+1);

		PrintPrefix(os,level);
		os<<"Right Hand Side:\n";

		right_child_->PrintNode(os,level+1);
		PrintPrefix(os,level);

		os<<"}\n";
	}


public:

    virtual ~NodeAssignment();

    DECLARE_ASNODE_MEMORY_FUNC(NodeAssignment)
private:
    ASNode* left_child_ , *right_child_;
};

class NodeIf : public ASNode {
public:
    NodeIf() :
        ASNode( ASNode::NODE_IF ) ,
        condition_node_(NULL),
        body_(NULL){}

    typedef std::list<ASNode*> NodeList;
    const NodeList& branch_list() const {
        return branch_list_;
    }

    void AppendBranch( ASNode* n ) {
        branch_list_.push_back(n);
    }

    ASNode* condition_node() const {
        return condition_node_;
    }

    void set_condition_node( ASNode* n ) {
        n->set_parent(this);
        condition_node_ = n;
    }

    ASNode* body() const {
        return body_;
    }

    void set_body( ASNode* n ) {
        body_ = n;
    }

	virtual void PrintNode(std::ostream& os , int level= 0);

public:

    virtual ~NodeIf();

    DECLARE_ASNODE_MEMORY_FUNC(NodeIf)

private:
    ASNode* condition_node_;
    ASNode* body_;
    NodeList branch_list_;
};


class NodeElseIf : public ASNode {
public:
	NodeElseIf():
	  ASNode( ASNode::NODE_ELSEIF ) ,
	  condition_node_(NULL) ,
	  body_(NULL){}

	ASNode* condition_node() const {
		return condition_node_;
	}

	void set_condition_node( ASNode* cn ) {
		condition_node_ = cn;
	}

	ASNode* body() const {
		return body_;
	}

	void set_body( ASNode* n ) {
		body_ = n;
	}

	virtual void PrintNode(std::ostream& os , int level = 0 ) {
		PrintPrefix(os,level);
		os<<"ElseIf:{\n";
		PrintPrefix(os,level);
		os<<"Condition:\n";
		condition_node_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"Body:\n";
		body_->PrintNode(os,level+1);
		os<<"}\n";
	}

public:

	virtual ~NodeElseIf();

	DECLARE_ASNODE_MEMORY_FUNC(NodeElseIf)

private:
	ASNode* body_;
	ASNode* condition_node_;
};

class NodeElse : public ASNode {
public:
	NodeElse():
	  ASNode( ASNode::NODE_ELSE ),
	  body_(NULL){}

	ASNode* body() const {
		return body_;
	}

	void set_body( ASNode* n ) {
		body_ = n;
	}

	virtual void PrintNode(std::ostream& os , int level  = 0 ) {
		PrintNode(os,level);
		os<<"Else:{\n";
		PrintNode(os,level);
		os<<"Body:\n";
		body_->PrintNode(os,level+1);
		PrintNode(os,level);
		os<<"}\n";
	}

public:

	virtual ~NodeElse();
	DECLARE_ASNODE_MEMORY_FUNC(NodeElse)

private:
	ASNode* body_;
};

class NodeFor : public ASNode {
public:
    NodeFor() :
        ASNode( ASNode::NODE_FOR ),
        initial_node_(NULL),
        step_node_(NULL),
        condition_node_(NULL),
        body_(NULL){}

    ASNode* initial_node() const {
        return initial_node_;
    }

    ASNode* step_node() const {
        return step_node_;
    }

    ASNode* condition_node() const {
        return condition_node_;
    }

    ASNode* body() const {
        return body_;
    }

    void set_initial_node( ASNode* n ) {
        n->set_parent(this);
        initial_node_ = n;
    }

    void set_step_node( ASNode* n ) {
        n->set_parent(this);
        step_node_ = n;
    }

    void set_condition_node( ASNode* n ) {
        n->set_parent(this);
        condition_node_ = n;
    }

    void set_body( ASNode* n ) {
        n->set_parent(this);
        body_ = n;
    }

	virtual void PrintNode( std::ostream& os , int level = 0 ) {
		PrintPrefix(os,level);
		os<<"For:{\n";
		PrintPrefix(os,level);
		os<<"Initial:\n";
		initial_node_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"Condition:\n";
		condition_node_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"Step:\n";
		step_node_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"Body:\n";
		body_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"}\n";
	}

public:

    DECLARE_ASNODE_MEMORY_FUNC(NodeFor)

    virtual ~NodeFor();
private:
    ASNode* body_ ;
    ASNode* initial_node_;
    ASNode* step_node_;
    ASNode* condition_node_;
};

class NodeForeach  : public ASNode {
public:
    NodeForeach() :
        ASNode( ASNode::NODE_FOREACH ),
        list_node_(NULL),
        body_(NULL){}

    ASNode* list_node() const {
        return list_node_;
    }

    ASNode* body() const {
        return body_;
    }

    void set_list_node( ASNode* n ) {
        n->set_parent(this);
        list_node_ = n;
    }

    void set_body( ASNode* n ) {
        n->set_parent(this);
        body_ =  n;
    }

	virtual void PrintNode(std::ostream& os , int level = 0 ) {
		PrintPrefix(os,level);
		os<<"Foreach:{\n";
		PrintPrefix(os,level);
		os<<"ListCondition:\n";
		list_node_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<"Body:\n";
		body_->PrintNode(os,level);
		PrintPrefix(os,level);
		os<<"}\n";
	}

public:

    virtual ~NodeForeach();

    DECLARE_ASNODE_MEMORY_FUNC(NodeForeach)
private:
    ASNode* list_node_;
    ASNode* body_;

};

class NodeWhile : public ASNode {
public:
    NodeWhile() :
        ASNode( ASNode::NODE_WHILE ) ,
        condition_node_(NULL),
        body_(NULL){}

public:

    ASNode* condition_node() const {
        return condition_node_;
    }

    ASNode* body() const {
        return body_;
    }

    void set_condition_node( ASNode* n ) {
        n->set_parent(this);
        condition_node_ = n;
    }

    void set_body( ASNode* n ) {
        n->set_parent(this);
        body_ = n;
    }

	virtual void PrintNode(std::ostream& os , int level =0 );

public:

    virtual ~NodeWhile();

    DECLARE_ASNODE_MEMORY_FUNC(NodeWhile)

private:
    ASNode* body_ , *condition_node_;
};

class NodeDefineFunc : public ASNode {
public:
    NodeDefineFunc() :
        ASNode(ASNode::NODE_DEFINE_FUNC),
        func_name_(NULL),
        body_(NULL){}

    typedef std::list<ASNode*> NodeList;

    const NodeList& parameter_list() const {
        return parameter_list_;
    }

    void AppendParameter( ASNode* n ) {
        n->set_parent(this);
        parameter_list_.push_back(n);
    }

    ASNode* func_name() const {
        return func_name_;
    }

    ASNode* body() const {
        return body_;
    }

    void set_func_name( ASNode* n ) {
        n->set_parent(this);
        func_name_ = n;
    }

    void set_body( ASNode* n ) {
        n->set_parent(this);
        body_ = n;
    }

	virtual void PrintNode(std::ostream& os , int level=0 );

public:

    virtual ~NodeDefineFunc();

    DECLARE_ASNODE_MEMORY_FUNC(NodeDefineFunc)

private:
    ASNode* body_ , *func_name_;
    NodeList parameter_list_;
};


class NodeReturn : public ASNode {
public:
	NodeReturn():
	  ASNode( ASNode::NODE_RETURN ),
	  value_(NULL){}

	ASNode* value() const {
		return value_;
	}

	void set_value( ASNode* n ) {
		value_ = n;
	}

	virtual void PrintNode(std::ostream& os , int level=0 ) {
		PrintPrefix(os,level);
		os<<"Return:";
		value_->PrintNode(os,level+1);
	}
public:
	DECLARE_ASNODE_MEMORY_FUNC(NodeReturn)
	virtual ~NodeReturn() { delete value_; }
private:
	ASNode* value_;
};

// The node can accepts 2 types of index. One is the key , the other
// is the integer index. We keep track of all type of index in 2
// separate objects. std::set<int> for index and std::set<std::string>
// for string/symbol key. Everytime, the insertion happens ,it will
// internally check weather such definition is allowed or not.
class NodeDefineList : public ASNode {
public:
    NodeDefineList() :
        ASNode( ASNode::NODE_DEFINE_LIST ){}
    // The definition nodes are stored inside of this
	// list instead of using map.
	typedef std::list<ASNode*> DefineList;
	// The key are storing inside of this 
	// unique.
	typedef std::set<std::string> KeyList;
	typedef std::set<int> IndexList;

	const DefineList& define_list() const {
		return define_list_;
	}

	const KeyList& key_list() const {
		return key_list_;
	}

	const IndexList& index_list() const {
		return index_list_;
	}

	bool AppendDefinition( ASNode* n );

	virtual void PrintNode(std::ostream& os , int level =0 );

public:

    virtual ~NodeDefineList();


    DECLARE_ASNODE_MEMORY_FUNC(NodeDefineList)

private:
    DefineList define_list_;
	KeyList key_list_;
	IndexList index_list_;
};

class NodeDefineListAssignment : public ASNode {
public:
	NodeDefineListAssignment():
	  ASNode( ASNode::NODE_DEFINE_LIST_ASSIGNMENT ),
	  value_node_(NULL),
	  name_(NULL){}

	ASNode* value_node() const {
		return value_node_;
	}

	void set_value_node( ASNode* v ) {
		value_node_ = v;
	}

	ASNode* name() const {
		return name_;
	}

	void set_name( ASNode* n ) {
		name_ = n;
	}

	virtual void PrintNode(std::ostream& os , int level =0 ) {
		name_->PrintNode(os,level+1);
		PrintPrefix(os,level);
		os<<" = \n";
		value_node_->PrintNode(os,level+1);
	}

public:

	DECLARE_ASNODE_MEMORY_FUNC(NodeDefineListAssignment)

	virtual ~NodeDefineListAssignment();

private:
	ASNode* name_;
	ASNode* value_node_;
};

class NodeInt : public ASNode {
public:
    NodeInt() :
        ASNode(ASNode::NODE_INT),
        value_(0){}

	NodeInt( int i ) :
		ASNode(ASNode::NODE_INT),
		value_(i){}


    int value() const {
        return value_;
    }

    void set_value( int i ) {
        value_ = i ;
    }


	virtual void PrintNode( std::ostream& os , int level =0 ) {
		PrintPrefix(os,level);
		os<<"<int>:"<<value_<<"\n";
	}
	

public:

    virtual ~NodeInt() {}

    DECLARE_ASNODE_MEMORY_FUNC(NodeInt)

private:
    int value_;
};

class NodeFloat : public ASNode {
public:
    NodeFloat() :
        ASNode( ASNode::NODE_FLOAT ),
        value_(0.0f){}

	NodeFloat( double f ) :
		ASNode( ASNode::NODE_FLOAT ),
		value_(f){}

    double value() const {
        return value_;
    }

    void set_value( double f ) {
        value_ = f;
    }

	virtual void PrintNode( std::ostream& os , int level =0 ) {
		PrintPrefix(os,level);
		os<<"<float>:"<<value_<<"\n";
	}

public:

    virtual ~NodeFloat() {}

    DECLARE_ASNODE_MEMORY_FUNC(NodeFloat)
private:

    double value_;
};

class NodeBoolean : public ASNode {
public:
    NodeBoolean():
        ASNode( ASNode::NODE_BOOLEAN ) ,
        value_(false){}

	NodeBoolean( bool b ) :
		ASNode( ASNode::NODE_BOOLEAN ),
		value_(b){}

    bool value() const {
        return value_;
    }

    void set_value( bool v ) {
        value_ = v;
    }

	virtual void PrintNode( std::ostream& os, int level =0  ) {
		PrintPrefix(os,level);
		os<<"<boolean>:"<<std::boolalpha<<value_<<"\n";
	}

    virtual ~NodeBoolean() {}

    DECLARE_ASNODE_MEMORY_FUNC(NodeBoolean)

private:
    bool value_;
};

class NodeString : public ASNode {
public:
	NodeString():
	  ASNode(ASNode::NODE_STRING){}

	NodeString( const std::string& v ) :
	  ASNode( ASNode::NODE_STRING ),
		  value_(v){}

	const std::string& value() const {
		return value_;
	}

	void set_value( const std::string& v ) {
		value_ = v;
	}

	virtual void PrintNode( std::ostream& os, int level =0 ) {
		PrintPrefix(os,level);
		os<<"<string>:"<<value_<<"\n";
	}

	DECLARE_ASNODE_MEMORY_FUNC(NodeString)

private:
	std::string value_;
};


class NodeNull : public ASNode {
public:
	NodeNull():
	  ASNode( ASNode::NODE_NULL ){}

public:

	virtual void PrintNode(std::ostream& os , int level=0) {
		PrintPrefix(os,level);
		os<<"<null>:null\n";
	}

public:

	virtual ~NodeNull(){}
	DECLARE_ASNODE_MEMORY_FUNC(NodeNull)

};


class NodeSymbol : public ASNode {
public:
    NodeSymbol() :
        ASNode( ASNode::NODE_SYMBOL ) {}


	NodeSymbol( const std::string& v ) :
		ASNode( ASNode::NODE_SYMBOL ),
			variable_name_(v){}

    const std::string& variable_name() const {
        return variable_name_;
    }

    void set_variable_name( const std::string& val ) {
        variable_name_ = val;
    }

	virtual void PrintNode( std::ostream& os, int level =0 ) {
		PrintPrefix(os,level);
		os<<"<symbol>:"<<variable_name_<<"\n";
	}

    virtual ~NodeSymbol() {}

    DECLARE_ASNODE_MEMORY_FUNC(NodeSymbol)

private:
	// the variable name
    std::string variable_name_;
};

class NodeKeyword : public ASNode {
public:
    NodeKeyword() :
        ASNode( ASNode::NODE_KEYWORD ){}

	NodeKeyword( int tk ) :
		ASNode( ASNode::NODE_KEYWORD ),
		token_(tk){}

    int token() const {
        return token_;
    }

    void set_token( int t ) {
        token_ = t;
    }

	virtual void PrintNode( std::ostream& os, int level =0 ) {
		PrintPrefix(os,level);
		os<<"<keyword>:"<<Token::GetTokenName(token_)<<"\n";
	}

    DECLARE_ASNODE_MEMORY_FUNC(NodeKeyword)

private:
    int token_;
};

class NodeVarDeclaration : public ASNode {
public:
	NodeVarDeclaration() :
	  ASNode( ASNode::NODE_LHS_VARIABLE ) ,
	  decorator_(Token::TT_GLOBAL){}
	virtual ~NodeVarDeclaration(){}
public:

	int decorator() const {
		return decorator_;
	}

	void set_decorator( int t ) {
		decorator_ = t;
	}

	virtual void PrintNode(std::ostream& os , int level /* = 0 */) {
		PrintPrefix(os,level);
		os<<"LeftHandSide:("
			<<Token::GetTokenName(decorator_)<<","
			<<name_<<")\n";
	}

	const std::string& name() const {
		return name_;
	}

	void set_name( const std::string& n ) {
		name_ = n;
	}

	DECLARE_ASNODE_MEMORY_FUNC(NodeVarDeclaration)

private:
	int decorator_;
	std::string name_;
};


class NodeChunk : public ASNode {
public:
	NodeChunk():
	  ASNode( ASNode::NODE_CHUNK ) {}


	typedef std::list<ASNode*> NodeList;

	const NodeList& node_list() const {
		return node_list_;
	}

	void AppendStatement( ASNode* n ) {
		node_list_.push_back(n);
	}

	virtual void PrintNode(std::ostream& os , int level =0 );

public:

	virtual ~NodeChunk();

	DECLARE_ASNODE_MEMORY_FUNC(NodeChunk)

private:

	NodeList node_list_;

};

DECLARE_ASNODE(NodeKeyword,ASNode::NODE_KEYWORD)
DECLARE_ASNODE(NodeUnary,ASNode::NODE_UNARY)
DECLARE_ASNODE(NodeExpression,ASNode::NODE_EXPRESSION)
DECLARE_ASNODE(NodeFuncInvoke,ASNode::NODE_FUNC_INVOKE)
DECLARE_ASNODE(NodeAssignment,ASNode::NODE_ASSIGNMENT)
DECLARE_ASNODE(NodeIf,ASNode::NODE_IF)
DECLARE_ASNODE(NodeElseIf,ASNode::NODE_ELSEIF)
DECLARE_ASNODE(NodeElse,ASNode::NODE_ELSE)
DECLARE_ASNODE(NodeFor,ASNode::NODE_FOR)
DECLARE_ASNODE(NodeForeach,ASNode::NODE_FOREACH)
DECLARE_ASNODE(NodeWhile,ASNode::NODE_WHILE)
DECLARE_ASNODE(NodeDefineFunc,ASNode::NODE_DEFINE_FUNC)
DECLARE_ASNODE(NodeDefineList,ASNode::NODE_DEFINE_LIST)
DECLARE_ASNODE(NodeDefineListAssignment,ASNode::NODE_DEFINE_LIST_ASSIGNMENT)
DECLARE_ASNODE(NodeListAccessor,ASNode::NODE_LIST_ACCESSOR)
DECLARE_ASNODE(NodeInt,ASNode::NODE_INT)
DECLARE_ASNODE(NodeFloat,ASNode::NODE_FLOAT)
DECLARE_ASNODE(NodeBoolean,ASNode::NODE_BOOLEAN)
DECLARE_ASNODE(NodeString,ASNode::NODE_STRING)
DECLARE_ASNODE(NodeSymbol,ASNode::NODE_SYMBOL)
DECLARE_ASNODE(NodeVarDeclaration,ASNode::NODE_LHS_VARIABLE)
DECLARE_ASNODE(NodeChunk,ASNode::NODE_CHUNK)
DECLARE_ASNODE(NodeNull,ASNode::NODE_NULL)
DECLARE_ASNODE(NodeReturn,ASNode::NODE_RETURN)

template<typename T>
inline T* ASNode::TryCast() const {
    if( node_type_ != asnode_id<T>::type_id )
        return NULL;
    return static_cast<T*>(const_cast<ASNode*>(this));
}

template<typename T>
inline T* ASNode::EnsureCast() const {
    assert( node_type_ == asnode_id<T>::type_id );
    return static_cast<T*>(const_cast<ASNode*>(this));
}



} // namespace internal
} // namespace sscript

#endif // ASNODE_H
